#include "power.h"
#include "power_charger.h"

#if USE_POWER_MODULE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "../../board.h"
#include "charger_config.h"
#include "lvgl/lvgl.h"

//#define printf cplog_printf
#define TICK1S        1000
#define SECOND        *TICK1S

#define MILLI_SECOND  SECOND / 1000
#define MILLI_SECONDS MILLI_SECOND
#define SECONDS       SECOND
#define MINUTE        *(60 SECOND)
#define MINUTES       MINUTE

#define PMIC_COUNT_CHG_STATUS_STABLE         (10)
#define PMIC_MV_OFFSET_CHG_PHASE_2           (70)
#define PMIC_MV_OFFSET_CHG_FULL_COMPENSATION 100/*20//(-10) */

#define PMIC_INTERVAL_CHG_ON_LONG      (10 MINUTES)
#define PMIC_INTERVAL_CHG_ON_MEDIUM    (6 MINUTES)
#define PMIC_CHG_TIMEOUT               (240 MINUTES)
#define PMIC_INTERVAL_CHG_MEAS_STABLE  (1 MINUTE)

#define PMIC_COUNT_CHG_CHR_VOLT_STABLE (5)

#define PMIC_MV_OFFSET_CHG_CHR_VOLT    (100)

typedef enum {
  PMIC_CHARGING_STAGE_OFF,
  PMIC_CHARGING_STAGE_MEAS_DELAY,
  PMIC_CHARGING_STAGE_MEAS,
  PMIC_CHARGING_STAGE_PULSE,
  PMIC_CHARGING_STAGE_ON,
} PMIC_CHARGING_STAGE_T;

PMIC_CHARGER_STATE_T g_pmicChargerState;
//static uint16_t g_pmicBattVoltAry[PMIC_COUNT_CHG_STATUS_STABLE];
/* Charger charging stage */
static PMIC_CHARGING_STAGE_T g_pmicChargingStage = PMIC_CHARGING_STAGE_OFF;

static uint32_t g_pmicChargerFullDelayTime = 0;
/* The start time of the measurement delay */
extern uint8_t charger_present;
BOOL Battery_charge_full;
PMIC_CHARGE_EVENT_T charger_event;

extern PMIC_CONFIG_T *g_pmicConfig;

/* ============================================================================ */
#if 1 //defined (CONFIG_BOARD_CRANEM_EVB)
#define PM803_ETA4256CHARGEREN_GPIO   GPIO14
#define PM803_ETA4256CHARGERSTA_GPIO  GPIO13
#else
#define PM803_ETA4256CHARGEREN_GPIO   GPIO121
#define PM803_ETA4256CHARGERSTA_GPIO  GPIO124
#endif

static uint32_t charger_mfp_cfgs[] = {
    MFP_REG(GPIO_13) | MFP_AF0 | MFP_DRIVE_MEDIUM | MFP_PULL_LOW | MFP_SLEEP_FLOAT | MFP_LPM_EDGE_NONE,
    MFP_REG(GPIO_14) | MFP_AF0 | MFP_DRIVE_MEDIUM | MFP_PULL_LOW | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE,
    MFP_EOC
};

void Pm803_Eta4256ChargerEnonoff(unsigned int on_off)
{
    gpio_set_direction(PM803_ETA4256CHARGEREN_GPIO, GPIO_OUT);
    if(on_off) {
      gpio_output_set(PM803_ETA4256CHARGEREN_GPIO, 0);
    } else {
      gpio_output_set(PM803_ETA4256CHARGEREN_GPIO, 1);
    }
}

extern int GpioGetLevel(uint32_t portHandle);
#define CHARGER_IN_CHARGING    1
#define CHARGER_FINISHED       0
int Pm803_Eta4256GetChargerStatus(void)
{
    gpio_set_direction(PM803_ETA4256CHARGERSTA_GPIO, GPIO_IN);
    return (GpioGetLevel(PM803_ETA4256CHARGERSTA_GPIO) == 0?CHARGER_IN_CHARGING:CHARGER_FINISHED);
}

extern int16_t GetPm803VbatAdc(void);
extern unsigned pm812_get_batt_vol(void);
extern void ForceChargerFinished(BOOL stop);
extern int GetChargeStatus(void);

/* get soc from ocv: lookup table */
static int get_battery_soc_from_ocv(unsigned short ocv, unsigned short *bat_table)
{
    int i;
    int soc = 0;
    if(ocv >= bat_table[0]) {
      soc = 100;
    } else if(ocv < bat_table[100]) {
      soc = 0;
    } else {
      for(i = 1; i < 101; i++) {
        if((ocv < bat_table[i - 1]) && (ocv >= bat_table[i])) {
          soc = 100 - i;
          break;
        }
      }
    }
    return soc;
}

uint16_t pmic_GetGpadcBatteryLevel(void)
{
    return (uint16_t)pm812_get_batt_vol();
}

uint16_t pmic_GetBatteryLevel(uint8_t *pPercent)
{
    g_pmicChargerState.batteryLevel = pmic_GetGpadcBatteryLevel();

    if((g_pmicChargerState.batteryLevel != PMIC_BAD_VALUE) && (pPercent != NULL)) {
      *pPercent = pmic_BatteryLevelToPercent(g_pmicChargerState.batteryLevel);
    }

    return g_pmicChargerState.batteryLevel;
}

uint8_t pmic_BatteryLevelToPercent(uint16_t batteryLevel)
{
    int percent;
    /* build a % value */
    if(g_pmicConfig->Has_battery_discharger_table) {
      percent = get_battery_soc_from_ocv(batteryLevel, (unsigned short *)&(g_pmicConfig->BatteryDischarger_table));
    } else {
      percent = 100 * (batteryLevel - g_pmicConfig->powerDownVoltageMV) / (g_pmicConfig->batteryLevelFullMV - g_pmicConfig->powerDownVoltageMV);
    }
    if(percent <= 0) {
      return 0;
    } else if(percent >= 100) {
      return 100;
    } else {
      return percent;
    }
}

PMIC_CHARGER_STATUS_T pmic_GetChargerStatus(void)
{
    printf("pmic_GetChargerStatus: %d(unplug: 1, plug : 2)\n", g_pmicChargerState.status);
    return g_pmicChargerState.status;
}

void pmic_set_mppt(void)
{
#if 0
    pm813_auto_set_max_cc_current(g_pmicConfig->mppt_CurrentUpperLimit);  /*for mppt */
#endif
}

PMIC_CHARGER_STATUS_T Charger_check_State(PMU_CHR_STATUS_T status)
{
    //unsigned int vbat, Icurrnet, direction;
    PMIC_CHARGER_STATUS_T nextState = g_pmicChargerState.status;

    printf("g_pmicChargingStage =%x (off/meas_delay/meas/pulse/on)!!!\n", g_pmicChargingStage);/*debug test */
    if(Battery_charge_full) {
      if(pm812_get_batt_vol() + g_pmicConfig->recharger_vol_mV >= g_pmicConfig->batteryLevelFullMV) {
        if((g_pmicChargingStage == PMIC_CHARGING_STAGE_ON) && (get_time_ms()- g_pmicChargerFullDelayTime < PMIC_INTERVAL_CHG_ON_LONG)) {
          g_pmicChargingStage = PMIC_CHARGING_STAGE_OFF;
          nextState = PMIC_CHARGER_FULL_CHARGE;
          /*ForceChargerFinished(TRUE); */
          return nextState;
        } else if((get_time_ms()- g_pmicChargerFullDelayTime) >= PMIC_INTERVAL_CHG_ON_LONG) {
          Battery_charge_full = 0;
        }
      } else {
        Battery_charge_full = 0;
      }
    }

    switch(g_pmicChargingStage) {
    case PMIC_CHARGING_STAGE_ON:
      if(GetChargeStatus() == CHARGER_FINISHED) {
        printf("battery chargeing full !!!!!!\n");
        g_pmicChargingStage = PMIC_CHARGING_STAGE_OFF;
        nextState = PMIC_CHARGER_FULL_CHARGE;
        /*ForceChargerFinished(TRUE); */
        g_pmicChargerFullDelayTime = get_time_ms();
        Battery_charge_full = 1;
      }
      #if 0
      else if(pmic_get_charger_fsm() == FSM_FAULT) {
        nextState = PMIC_CHARGER_TIMED_OUT;
        printf("battery chargeing fault####\n");
        g_pmicChargingStage = PMIC_CHARGING_STAGE_OFF;
      }
      #endif
      break;
    case PMIC_CHARGING_STAGE_OFF:
      if(pm812_get_batt_vol() + g_pmicConfig->recharger_vol_mV >= g_pmicConfig->batteryLevelFullMV) {
        break;
      }
      g_pmicChargingStage = PMIC_CHARGING_STAGE_ON;
      nextState = PMIC_CHARGER_PULSED_CHARGE;
      ForceChargerFinished(0);
      Battery_charge_full = 0;
      printf("Charger_check_State: start charging~~~\n");
      break;
    default:
      break;
    }
    return nextState;
}

void ChargerManager(void)
{
    //uint16_t curBattVolt;
    PMU_CHR_STATUS_T status;
    PMIC_CHARGER_STATUS_T nextState = g_pmicChargerState.status;
    switch(charger_event) {
    case PMIC_CHARGE_DC_OFF:
      nextState = PMIC_CHARGER_UNPLUGGED;
      g_pmicChargingStage = PMIC_CHARGING_STAGE_OFF;
      break;
    case PMIC_CHARGE_DC_ON:
      g_pmicChargingStage = PMIC_CHARGING_STAGE_ON;
      ForceChargerFinished(0);
      charger_event = PMIC_CHARGE_TIMER;
      break;
    case PMIC_CHARGE_TIMER:
      if(nextState == PMIC_CHARGER_UNKNOWN ||
         nextState == PMIC_CHARGER_UNPLUGGED) {
        nextState = PMIC_CHARGER_PLUGGED;
      } else {
        /* Upper layer has known that charger is plugged in */
        nextState = Charger_check_State(status);
        if(nextState == PMIC_CHARGER_PLUGGED) {
          nextState = PMIC_CHARGER_FAST_CHARGE;
        }
      }
      break;
    default:
      break;
    }
    printf("charger: nextState=%d ,oldstatus=%d\n",
               nextState, g_pmicChargerState.status);
    if(nextState != g_pmicChargerState.status) {
      if(!charger_present) {
        nextState = PMIC_CHARGER_UNPLUGGED;
      }
      g_pmicChargerState.status = nextState;
    }
#if 0
    int batt_temp;
    /*add battery temp check */
    if(g_pmicConfig->Has_battery_temp) {
      batt_temp = Get_Battery_temp();
      if(batt_temp != 0xdeaddead) {
        if(batt_temp < 10) {
          pmic_cc_current_set(PMIC_CHARGER_200MA);
          PMIC_TRACE("Battery is cool!\n");
        } else if((batt_temp > 45) && (batt_temp < 60)) {
          pmic_vbat_set(VBAT_VOL_4V20);
          PMIC_TRACE("Battery is hot!\n");
        } else if(batt_temp >= 60) {
          ForceChargerFinished(TRUE);
          PMIC_TRACE("Battery too hot,pmd charger off!\n");
        }
        PMIC_TRACE("Battery temperature:%d!\n", batt_temp);
      }
    }
#endif
}

void pmic_InitCharger(VOID)
{
    int ret;
    g_pmicConfig = &g_tgtPmdCfg[0];

    charger_dump_config();
    mfp_config(charger_mfp_cfgs);

    ret = PM812_CHARGER_STATUS();
    if(ret != CHG_DISCONNECTED) {
      printf("pmic_InitCharger, charger connected: %d\n", ret);
      g_pmicChargerState.status = PMIC_CHARGER_PLUGGED;
      charger_event = PMIC_CHARGE_DC_ON;
      charger_present = 1;
    } else {
      printf("pmic_InitCharger, charger disconnected\n");
      g_pmicChargerState.status = PMIC_CHARGER_UNPLUGGED;    /*10s */
      charger_event = PMIC_CHARGE_DC_OFF;
      charger_present = 0;
    }
    //SetBatteryStatusHandler();
}

uint8_t pmic_GetPowerDownVolt(void)
{
    /*g_pmicConfig->powerDownVoltageMV = 3400; */
    return pmic_BatteryLevelToPercent(g_pmicConfig->powerDownVoltageMV);
}

void charger_dump_config(void)
{
    int i = 0;
    printf("batteryLevelFullMV=%d\n", g_pmicConfig->batteryLevelFullMV);
    printf("mppt_CurrentUpperLimit=%d\n", g_pmicConfig->mppt_CurrentUpperLimit);
    //printf("battery_cv_Voltage=%d\n", g_pmicConfig->battery_cv_Voltage);
    printf("termination_charger_Current=%d\n", g_pmicConfig->termination_charger_Current);
    printf("batteryIR=%d\n", g_pmicConfig->batteryIR);
    printf("recharger_vol_mV=%d\n", g_pmicConfig->recharger_vol_mV);
    printf("charger_rise_up_vol=%d\n", g_pmicConfig->charger_rise_up_vol);
    printf("Has_battery_temp=%d\n", g_pmicConfig->Has_battery_temp);

    if(g_pmicConfig->Has_battery_discharger_table) {
      printf("BatteryDischarger_table:\n");
      for(i = 0; i < 101; i++) {
        printf("%d, ", g_pmicConfig->BatteryDischarger_table[i]);
      }
      printf("\n");
    } else {
      printf("no Has_battery_discharger_table\n");
    }
}

BOOL get_battery_full_status(void)
{
    return Battery_charge_full;
}

#endif
